//
//  WDURLProtocol.m
//  WDLogicBehind
//
//  Created by Alean on 2022/12/1.
//

#import "WDURLProtocol.h"

#import "AFSecurityPolicy.h"
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/if.h>

#define IOS_CELLULAR    @"pdp_ip0"
#define IOS_WIFI        @"en0"
#define IOS_VPN         @"utun0"
#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

static BOOL useBackupDomain = NO;
static BOOL enableHTTPDNS = NO;
static BOOL enableBackupDomains = NO;

static NSString * const URLProtocolHandledKey = @"WDURLProtocolHandledKey";

@interface WDURLProtocol () <NSURLConnectionDelegate>

@property (nonatomic, strong) NSURLConnection *connection;

@end

@implementation WDURLProtocol

+ (void)disableHTTPDNS {
    enableHTTPDNS = NO;
    NSLog(@"disableHTTPDNS");
}

+ (void)disableBackupDomain {
    enableBackupDomains = NO;
    NSLog(@"disableBackupDomain");
}

+ (void)enableHTTPDNS {
    enableHTTPDNS = YES;
    NSLog(@"enableHTTPDNS");
}

+ (void)enableBackupDomain {
    enableBackupDomains = YES;
    NSLog(@"enableBackupDomain");
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    //只处理http和https请求
    NSString *scheme = [[request URL] scheme];
    if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
          [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)) {
        //看看是否已经处理过了，防止无限循环
        if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
            return NO;
        }
        
        if ([self isValidIP:[request.URL host]]) {
            return NO;
        }
        
        return YES;
    }
    return NO;
}

+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    mutableReqeust = [self redirectHostInRequset:mutableReqeust];
    return mutableReqeust;
}

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}

- (void)startLoading {
    //这里转发http请求，请求结果调用self.client 返回给客户端，如果返回结果显示域名出问题，替换域名，重新再请求。
    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
    //打标签，防止无限循环
    [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
    self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
    
//    [[[NSURLSession sharedSession] dataTaskWithRequest:mutableReqeust completionHandler:^(NSData * _Nullable _data, NSURLResponse * _Nullable _response, NSError * _Nullable _error) {
//
//    }] resume];
}

- (void)stopLoading {
    [self.connection cancel];
}

#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(nonnull NSURLAuthenticationChallenge *)challenge {
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    
    NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
    [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
    
//    NSString *host = [connection.currentRequest.allHTTPHeaderFields objectForKey:@"host"];
//    if ([[AFSecurityPolicy defaultPolicy] evaluateServerTrust:trust forDomain:host]) {
//        NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
//        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
//    }
//    else {
//        [challenge.sender cancelAuthenticationChallenge:challenge];
//    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
//    if (error) {
//        //判断域名是否出问题,如果出问题，重新请求。
//        BOOL useBackup = NO;
//        if (error.code == NSURLErrorCannotFindHost) {
//            NSLog(@"找不到域名对应的主机");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorCannotConnectToHost) {
//            NSLog(@"无法连接到主机");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorNetworkConnectionLost) {
//            NSLog(@"网络连接丢失");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorDNSLookupFailed) {
//            NSLog(@"DNS查找失败");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorSecureConnectionFailed) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorServerCertificateHasBadDate) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorServerCertificateUntrusted) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorServerCertificateHasUnknownRoot) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorServerCertificateNotYetValid) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorClientCertificateRejected) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else if (error.code == NSURLErrorClientCertificateRequired) {
//            NSLog(@"SSL证书问题");
//            useBackup = YES;
//        } else {
//            [self.client URLProtocol:self didFailWithError:error];
//        }
//
//        if (useBackup && enableBackupDomains) {
//            NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//
//            NSString *originHostString = [mutableReqeust.URL host];
//
//            if ([WDURLProtocol isValidIP:originHostString]) {
//                originHostString = [mutableReqeust.allHTTPHeaderFields objectForKey:@"host"];
//            }
//
//            if (originHostString == nil) {
//                originHostString = @"";
//            }
//
//            NSString *backupDomain = [[ZMYDomainManager instance] getBackupDomainWithHost:originHostString];
//
//            if (backupDomain.length > 0) {
//                // 替换host
//                NSString *urlString = [[connection.currentRequest.URL absoluteString] stringByReplacingOccurrencesOfString:originHostString withString:backupDomain];
//                NSURL *url = [NSURL URLWithString:urlString];
//                mutableReqeust.URL = url;
//
//                [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
//
//                self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
//                useBackupDomain = YES;
//
//                if ([ZMYDomainManager instance].dbblock) {
//
//                    NSString *bhost = [mutableReqeust.URL host];
//                    if (bhost == nil) {
//                        bhost = @"";
//                    }
//
//                    NSString *originUrlStr = [[mutableReqeust.URL absoluteString] stringByReplacingOccurrencesOfString:bhost withString:originHostString];
//
//                    if (originUrlStr == nil) {
//                        originUrlStr = @"";
//                    }
//
//                    [ZMYDomainManager instance].dbblock(@"1.1.11", originUrlStr, urlString, [NSString stringWithFormat:@"%ld",(long)error.code]);
//                }
//            } else {
//                [self.client URLProtocol:self didFailWithError:error];
//            }
//        } else {
//            [self.client URLProtocol:self didFailWithError:error];
//        }
//    } else {
//        [self.client URLProtocol:self didFailWithError:error];
//    }
    [self.client URLProtocol:self didFailWithError:error];
}

#pragma mark -- private
+ (NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request {
    if ([request.URL host].length == 0) {
        return request;
    }
    //    //先替换域名
    //    if (useBackupDomain && enableBackupDomains) {
    //
    //        NSString *originHostString = [request.URL host];
    //        NSString *backupDomain = [[ZMYDomainManager instance] getBackupDomainWithHost:originHostString];
    //        // 替换host
    //        if (backupDomain && backupDomain.length > 0) {
    //            NSString *urlString = [[request.URL absoluteString] stringByReplacingOccurrencesOfString:originHostString withString:backupDomain];
    //            NSURL *url = [NSURL URLWithString:urlString];
    //            request.URL = url;
    //        }
    //    }
    //
    //域名再替换成IP
    if (enableHTTPDNS && [self isIpv6] == NO) {
        //域名换成IP，防劫持
        NSString *originHostString = [request.URL host];
//        NSString *ip = [[ZMYDomainManager instance] getHostIP:originHostString];
        // 替换host
//        if (ip && ip.length > 0) {
//            NSString *urlString = [[request.URL absoluteString] stringByReplacingOccurrencesOfString:originHostString withString:ip];
//            NSURL *url = [NSURL URLWithString:urlString];
//            request.URL = url;
//
//            NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:request.allHTTPHeaderFields];
//            [dic setValue:[originHostString mutableCopy] forKey:@"host"];
//            request.allHTTPHeaderFields = dic;
//
//            if ([ZMYDomainManager instance].dnsblock) {
//                [ZMYDomainManager instance].dnsblock(@"1.1.11", originHostString, ip);
//            }
//        }
    }
    return request;
}

/**
 *判断一个字符串是否是一个IP地址
 **/
+ (BOOL)isValidIP:(NSString *)ipStr {
    if (nil == ipStr) {
        return NO;
    }
    NSString * string = @"((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))";
    NSPredicate * predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", string];
    return [predicate evaluateWithObject:ipStr];
}

+ (BOOL)isIpv6 {
    NSArray *searchArray =
    @[ IOS_VPN @"/" IP_ADDR_IPv6,
       IOS_VPN @"/" IP_ADDR_IPv4,
       IOS_WIFI @"/" IP_ADDR_IPv6,
       IOS_WIFI @"/" IP_ADDR_IPv4,
       IOS_CELLULAR @"/" IP_ADDR_IPv6,
       IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
    
    NSDictionary *addresses = [self getIPAddresses];
    
    __block BOOL isIpv6 = NO;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
        if ([key rangeOfString:@"ipv6"].length > 0  && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] ) {
            if ( ![addresses[key] hasPrefix:@"fe80"]) {
                isIpv6 = YES;
            }
        }
    } ];
    
    return isIpv6;
}

+ (NSDictionary *)getIPAddresses {
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
    // retrieve the current interfaces - returns 0 on success
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface=interfaces; interface; interface=interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; // deeply nested code harder to read
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET) {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

@end
